package com.evil.application.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSON;
import com.evil.application.constant.ApplicationConstant;
import com.evil.application.enums.form.control.ControlCodeEnum;
import com.evil.application.pojo.dto.form.control.code.ControlDTO;
import com.evil.application.pojo.dto.form.control.option.FormOptionRespDTO;
import com.evil.application.pojo.dto.form.control.option.OrderSelectOptionRespDTO;
import com.evil.application.pojo.dto.order.data.OrderControlDataRespDTO;
import com.evil.application.pojo.entity.ApplicationOrderData;
import com.evil.common.application.dto.judge.JudgeAnd;
import com.evil.common.application.dto.judge.JudgeOr;
import com.evil.common.application.dto.order.data.ControlDataDTO;
import com.evil.common.application.dto.order.data.ControlDataValueDTO;
import com.evil.common.application.dto.process.node.NodeBaseDTO;
import com.evil.common.application.dto.robot.RobotRuleDTO;
import com.evil.common.application.enums.judge.JudgeSignEnum;
import com.evil.common.application.enums.judge.MatchingTypeEnum;
import com.evil.common.application.enums.robot.RobotRuleChangeTypeEnum;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.file.util.PoiUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 应用订单工具类
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
public class OrderDataUtil {

    /**
     * 复制订单控件数据
     *
     * @param source source
     * @param target target
     */
    public static void copyControlData(ControlDataDTO source, ControlDataDTO target, List<FormOptionRespDTO> targetDataOptions) {
        ControlCodeEnum sourceControlCodeEnum = ControlCodeEnum.findByCode(source.getControlCode());
        ControlCodeEnum targetControlCodeEnum = ControlCodeEnum.findByCode(target.getControlCode());

        // 源数据 -> 下拉选择
        if (sourceControlCodeEnum.hasOptions()) {
            // 目标数据 -> 下拉选择
            if (targetControlCodeEnum.hasOptions()) {
                // 匹配下拉项
                List<FormOptionRespDTO> selOptions = source.getValues().stream()
                        .filter(e -> Objects.nonNull(e.getOtherInfo()))
                        .map(e -> BeanUtil.copyProperties(e.getOtherInfo(), FormOptionRespDTO.class))
                        .collect(Collectors.toList());
                target.setValues(OrderDataUtil.matchingOptions(selOptions, targetDataOptions));
            }
            // 目标数据 -> 成员选择
            else if (targetControlCodeEnum.hasMemberSelect()) {
                // 无法匹配
                target.setValues(new ArrayList<>());
            }
            // 目标数据 -> 数据引用
            else if (targetControlCodeEnum.hasQuote()) {
                // 直接使用数据id
                String dataValue = targetControlCodeEnum.getControlDataToString().apply(source);
                target.setValues(ListUtil.toList(new ControlDataValueDTO(source.getOrderDataId(), dataValue)));
            }
            // 目标数据 -> 普通
            else {
                // 复制控件值 value版
                target.setValues(CollUtil.toList(OrderDataUtil.copyControlValues(sourceControlCodeEnum, source.getValues())));
            }
        }
        // 源数据 -> 成员选择
        else if (sourceControlCodeEnum.hasMemberSelect()) {
            // 目标数据 -> 下拉选择
            if (targetControlCodeEnum.hasOptions()) {
                // 无法匹配
                target.setValues(new ArrayList<>());
            }
            // 目标数据 -> 成员选择
            else if (targetControlCodeEnum.hasMemberSelect()) {
                // 直接复制
                source.copyValue(target);
            }
            // 目标数据 -> 数据引用
            else if (targetControlCodeEnum.hasQuote()) {
                // 直接使用数据id
                String dataValue = targetControlCodeEnum.getControlDataToString().apply(source);
                target.setValues(ListUtil.toList(new ControlDataValueDTO(source.getOrderDataId(), dataValue)));
            }
            // 目标数据 -> 普通
            else {
                // 复制控件值 value版
                target.setValues(CollUtil.toList(OrderDataUtil.copyControlValues(sourceControlCodeEnum, source.getValues())));
            }
        }
        // 源数据 -> 数据引用
        else if (sourceControlCodeEnum.hasQuote()) {
            List<ControlDataValueDTO> dataValues = new ArrayList<>();
            Consumer<OrderSelectOptionRespDTO> copyValue;

            // 目标数据 -> 下拉选择
            if (targetControlCodeEnum.hasOptions()) {
                copyValue = f -> f.getSourceOptionIds().forEach(e -> dataValues.add(new ControlDataValueDTO(e, f.getOptionName()).setOtherInfo(f)));
            }
            // 目标数据 -> 成员选择
            else if (targetControlCodeEnum.hasMemberSelect()) {
                copyValue = f -> f.getSourceMemIds().forEach(e -> dataValues.add(new ControlDataValueDTO(e, f.getOptionName()).setOtherInfo(f)));
            }
            // 目标数据 -> 数据引用
            else if (targetControlCodeEnum.hasQuote()) {
                copyValue = f -> dataValues.add(new ControlDataValueDTO(f.getOptionId(), f.getOptionName()).setOtherInfo(f));
            }
            // 目标数据 -> 普通
            else {
                copyValue = f -> dataValues.add(new ControlDataValueDTO(f.getOptionName()));
            }

            source.getValues().forEach(dataValue -> OrderDataUtil
                    .optionalValueByOtherInfo(dataValue, OrderSelectOptionRespDTO.class, f -> f)
                    .ifPresent(copyValue));
            target.setValues(dataValues);
        }
        // 源数据 -> 普通
        else {
            // 目标数据 -> 下拉选择
            if (targetControlCodeEnum.hasOptions()) {
                // 选项值配置
                List<String> values = OrderDataUtil.getOrderDataValues(source.getValues());
                target.setValues(targetDataOptions.stream()
                        .filter(e -> values.contains(e.getOptionName()))
                        .map(e -> new ControlDataValueDTO(e.getOptionId(), e.getOptionValue()).setOtherInfo(e))
                        .toList());
            }
            // 目标数据 -> 成员选择
            else if (targetControlCodeEnum.hasMemberSelect()) {
                // 无法匹配
                target.setValues(new ArrayList<>());
            }
            // 目标数据 -> 数据引用
            else if (targetControlCodeEnum.hasQuote()) {
                // 直接使用数据id
                String dataValue = targetControlCodeEnum.getControlDataToString().apply(source);
                target.setValues(ListUtil.toList(new ControlDataValueDTO(source.getOrderDataId(), dataValue)));
            }
            // 目标数据 -> 普通
            else {
                // 直接复制
                source.copyValue(target);
            }
        }
    }

    /**
     * 匹配当前订单数据 是否满足条件
     *
     * @param judgeOrs      judgeOrs
     * @param targetDataMap targetDataMap
     * @return boolean
     */
    public static boolean handleCondition(Collection<JudgeOr> judgeOrs, Map<Long, ControlDataDTO> targetDataMap, Consumer<JudgeAnd> dynamic) {
        return OrderDataUtil.handleCondition(judgeOrs, new HashMap<>(), targetDataMap, new HashMap<>(), dynamic);
    }

    /**
     * 订单数据 条件判断
     * TODO 目前只不匹配表格数据
     * FIXME 目前只匹配下拉项，之后还需要人员、部门
     *
     * @param judgeOrs            条件列表
     * @param sourceDataMap       sourceDataMap（当前数据 如果是匹配字段会被塞到Judge里面 筛选数据）
     * @param targetDataMap       targetDataMap（目标数据 也就是key 需要被筛选的数据）
     * @param targetDataOptionMap targetDataOptionMap（目标数据 下拉项 key=controlId 动态匹配：同名匹配）
     * @return boolean
     */
    public static boolean handleCondition(Collection<JudgeOr> judgeOrs,
                                          Map<Long, ControlDataDTO> sourceDataMap,
                                          Map<Long, ControlDataDTO> targetDataMap,
                                          Map<Long, List<FormOptionRespDTO>> targetDataOptionMap,
                                          Consumer<JudgeAnd> dynamic) {
        // 复制一份条件（防止影响重复调用）
        return JudgeOr.copy(judgeOrs).stream().anyMatch(or -> or.getJudgeAnd().stream().allMatch(and -> {
            if (targetDataMap.containsKey(and.getControlId())) {
                ControlDataDTO targetData = targetDataMap.get(and.getControlId());
                List<String> key = OrderDataUtil.getControlValues(targetData);

                switch (MatchingTypeEnum.isExistById(and.getMatchingType())) {
                    case CUSTOM:
                        // 自定义
                        break;
                    case MATCHING_FIELD:
                        // 匹配字段
                        if (sourceDataMap.containsKey(and.getTargetId())) {
                            ControlDataDTO sourceData = sourceDataMap.get(and.getTargetId());

                            List<FormOptionRespDTO> controlOptions = targetDataOptionMap.getOrDefault(and.getControlId(), new ArrayList<>());
                            ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(sourceData.getControlCode());
                            if (controlCodeEnum.hasOptions()) {
                                // 下拉项
                                List<FormOptionRespDTO> selOptions = sourceData.getValues().stream()
                                        .filter(e -> Objects.nonNull(e.getOtherInfo()))
                                        .map(e -> BeanUtil.copyProperties(e.getOtherInfo(), FormOptionRespDTO.class))
                                        .collect(Collectors.toList());
                                // 匹配相同下拉项
                                sourceData.setValues(OrderDataUtil.matchingOptions(selOptions, controlOptions));
                            }
                            and.setValues(OrderDataUtil.getControlValues(sourceData));
                        }
                        break;
                    case DYNAMIC:
                        // 动态
                        dynamic.accept(and);
                        break;
                    default:
                        throw MatchingTypeEnum.getBusinessException();
                }
                return OrderDataUtil.handleCondition(and, key);
            }
            return false;
        }));
    }

    /**
     * 处理条件中匹配字段
     *
     * @param judgeOrs      judgeOrs
     * @param sourceDataMap sourceDataMap
     */
    public static void handleMatchingCondition(Collection<JudgeOr> judgeOrs, Map<Long, ControlDataDTO> sourceDataMap, Consumer<JudgeAnd> dynamic) {
        judgeOrs.forEach(or -> or.getJudgeAnd().forEach(and -> {
            switch (MatchingTypeEnum.isExistById(and.getMatchingType())) {
                case CUSTOM:
                    // 自定义
                    break;
                case MATCHING_FIELD:
                    // 匹配字段
                    if (sourceDataMap.containsKey(and.getTargetId())) {
                        ControlDataDTO sourceData = sourceDataMap.get(and.getTargetId());
                        and.setValues(OrderDataUtil.getControlValues(sourceData));
                    }
                    break;
                case DYNAMIC:
                    // 动态
                    dynamic.accept(and);
                    break;
                default:
                    throw MatchingTypeEnum.getBusinessException();
            }
        }));
    }

    /**
     * 数据条件判断
     *
     * @param and and
     * @param key key
     * @return boolean
     */
    public static boolean handleCondition(JudgeAnd and, List<String> key) {
        Optional<JudgeSignEnum> judgeSignEnumOptional = JudgeSignEnum.findById(and.getJudgeSign());
        if (!judgeSignEnumOptional.isPresent()) {
            return false;
        }
        Optional<ControlCodeEnum> controlCodeEnumOptional = ControlCodeEnum.isExistByCode(and.getControlCode());
        if (!controlCodeEnumOptional.isPresent()) {
            return true;
        }
        return controlCodeEnumOptional.get().getJudgeSigns().applyJudgeSigns(judgeSignEnumOptional.get(), key, and.getValues());
    }

    /**
     * 规则匹配
     *
     * @param robotRules    规则列表
     * @param judgeOrs      筛选条件
     * @param sourceDataMap sourceDataMap（当前数据）
     * @param targetDataDTO targetDataDTO
     */
    public static void ruleMatching(List<RobotRuleDTO> robotRules,
                                    Collection<JudgeOr> judgeOrs,
                                    Map<Long, ControlDataDTO> sourceDataMap,
                                    OrderControlDataRespDTO targetDataDTO,
                                    Function<ControlDTO, ControlDataDTO> generateData,
                                    Consumer<JudgeAnd> dynamicJudge,
                                    Consumer<RobotRuleDTO> dynamicRule) {
        Map<Long, ControlDTO> targetControlMap = targetDataDTO.getControlMap();
        Map<Long, ControlDataDTO> targetDataMap = targetDataDTO.getControlDataMap();
        Map<Long, List<FormOptionRespDTO>> targetControlOptionMap = targetDataDTO.getControlOptionsMap();

        // 从map中获取控件值，若不存在则初始化新控件数据 并且put到map中
        BiFunction<ControlDTO, Map<Long, ControlDataDTO>, ControlDataDTO> getControlDataForMap = (controlDTO, map) -> {
            if (map.containsKey(controlDTO.getControlId())) {
                return map.get(controlDTO.getControlId());
            } else {
                ControlDataDTO controlData = generateData.apply(controlDTO);
                map.put(controlDTO.getControlId(), controlData);
                return controlData;
            }
        };

        // 复制一份规则（防止影响重复调用）
        RobotRuleDTO.copy(robotRules).forEach(robotRule -> {
            MatchingTypeEnum ruleMatchingType = MatchingTypeEnum.isExistById(robotRule.getMatchingType());
            // 获取目标控件 存在后往下执行
            OrderDataUtil.getControlByMap(targetControlMap, robotRule.getRuleTargetId()).ifPresent(targetControl -> {
                // 获取目标控件数据，不存在则生成新的空白控件数据
                ControlDataDTO targetData = getControlDataForMap.apply(targetControl, targetDataMap);
                // 表格规则
                if (ControlCodeEnum.TABLE.getCode().equals(targetData.getControlCode())) {
                    // 表格子控件map
                    Map<Long, ControlDTO> childTargetControlMap = StreamUtil.toOrderlyMapK(targetControl.getChildControls(), ControlDTO::getControlId);
                    // 规则变更类型
                    RobotRuleChangeTypeEnum changeTypeEnum = RobotRuleChangeTypeEnum.isExistById(robotRule.getChangeType());
                    switch (changeTypeEnum) {
                        case ADD:
                        case COVER:
                            // 表格数据map
                            Map<Integer, Map<Long, ControlDataDTO>> tableDataMap = new LinkedHashMap<>();
                            if (RobotRuleChangeTypeEnum.COVER == changeTypeEnum) {
                                // 覆盖数据，需要先获取原数据
                                tableDataMap.putAll(OrderDataUtil.tableDataToMap(targetData.getTableValues()));
                            }
                            // 如果匹配到一个控件值，则表格整列 覆盖值
                            Map<Long, ControlDataDTO> justMatchingOne = new LinkedHashMap<>();
                            robotRule.getChildren().forEach(childRule -> {
                                MatchingTypeEnum childRuleMatchingType = MatchingTypeEnum.isExistById(childRule.getMatchingType());
                                switch (childRuleMatchingType) {
                                    case CUSTOM:
                                        // 自定义 (添加数据 才有)
                                        Map<Long, ControlDataDTO> firstRow = tableDataMap.getOrDefault(0, new LinkedHashMap<>());
                                        OrderDataUtil.getControlByMap(childTargetControlMap, childRule.getRuleTargetId()).ifPresent(childTargetControl -> {
                                            ControlDataDTO childTargetData = getControlDataForMap.apply(childTargetControl, firstRow);
                                            childTargetData.setValues(childRule.getValues());
                                        });
                                        break;
                                    case MATCHING_FIELD:
                                        // 匹配字段 （覆盖数据只能匹配字段）
                                        List<ControlDataDTO> dataList = OrderDataUtil.getOrderDataByMap(sourceDataMap, childRule.getRuleSourceId());
                                        // 如果匹配到一个控件值，则表格整列 覆盖值
                                        if (dataList.size() == 1) {
                                            ControlDataDTO controlDataDTO = dataList.get(0);
                                            justMatchingOne.put(controlDataDTO.getControlId(), controlDataDTO);
                                        }
                                        // 把数据插入到目标中
                                        for (AtomicInteger i = new AtomicInteger(); i.get() < dataList.size(); i.getAndIncrement()) {
                                            Map<Long, ControlDataDTO> row = tableDataMap.getOrDefault(i.get(), new LinkedHashMap<>());
                                            // 获取表格子控件信息
                                            OrderDataUtil.getControlByMap(childTargetControlMap, childRule.getRuleTargetId()).ifPresent(childTargetControl -> {
                                                // 获取表格指定格子
                                                ControlDataDTO childTargetData = getControlDataForMap.apply(childTargetControl, row);
                                                ControlDataDTO sourceControlData = dataList.get(i.get());
                                                // 格子下拉项
                                                List<FormOptionRespDTO> targetDataOptions = targetControlOptionMap.getOrDefault(childRule.getRuleTargetId(), new ArrayList<>());
                                                // 复制值
                                                OrderDataUtil.copyControlData(sourceControlData, childTargetData, targetDataOptions);
                                                // 补充到行
                                                row.put(childTargetData.getControlId(), childTargetData);
                                            });
                                            tableDataMap.put(i.get(), row);
                                        }
                                        break;
                                    case DYNAMIC:
                                        // 动态
                                        dynamicRule.accept(robotRule);
                                        targetData.setValues(robotRule.getValues());
                                        break;
                                    default:
                                        throw MatchingTypeEnum.getBusinessException();
                                }
                            });
                            // 表格整列 覆盖值
                            OrderDataUtil.modifyTableCell(justMatchingOne, tableDataMap, childTargetControlMap, targetControlOptionMap, getControlDataForMap);

                            List<List<ControlDataDTO>> tableValues = tableDataMap.values().stream().map(e -> new ArrayList<>(e.values())).collect(Collectors.toList());
                            if (RobotRuleChangeTypeEnum.COVER == changeTypeEnum) {
                                // 覆盖数据
                                targetData.setTableValues(tableValues);
                            } else {
                                // 新增数据
                                targetData.getTableValues().addAll(tableValues);
                            }
                            break;
                        case UPDATE:
                            // 更新数据
                            List<JudgeOr> tableJudgeOr = OrderDataUtil.filterJudgeOrs(judgeOrs, childTargetControlMap.keySet(), null);
                            if (tableJudgeOr.isEmpty()) {
                                // 更新数据 必须要有一条关于表格的筛选条件，否则就会整个表格更新了
                                return;
                            }
                            targetData.getTableValues().forEach(row -> {
                                Map<Long, ControlDataDTO> rowMap = StreamUtil.toOrderlyMapK(row, ControlDataDTO::getControlId);
                                if (OrderDataUtil.handleCondition(tableJudgeOr, rowMap, dynamicJudge)) {
                                    // 当前行 中的
                                    robotRule.getChildren().forEach(childRule -> OrderDataUtil.getControlDataByMap(rowMap, childRule.getRuleTargetId()).ifPresent(childTargetData -> {
                                        MatchingTypeEnum childRuleMatchingType = MatchingTypeEnum.isExistById(childRule.getMatchingType());
                                        switch (childRuleMatchingType) {
                                            case CUSTOM:
                                                // 自定义
                                                childTargetData.setValues(childRule.getValues());
                                                break;
                                            case MATCHING_FIELD:
                                                // 匹配字段
                                                OrderDataUtil.getControlDataByMap(sourceDataMap, childRule.getRuleSourceId()).ifPresent(sourceControlData -> {
                                                    // 格子下拉项
                                                    List<FormOptionRespDTO> targetDataOptions = targetControlOptionMap.getOrDefault(childRule.getRuleTargetId(), new ArrayList<>());
                                                    // 复制值
                                                    OrderDataUtil.copyControlData(sourceControlData, childTargetData, targetDataOptions);
                                                });
                                                break;
                                            case DYNAMIC:
                                                // 动态
                                                dynamicRule.accept(robotRule);
                                                targetData.setValues(robotRule.getValues());
                                                break;
                                            default:
                                                throw MatchingTypeEnum.getBusinessException();
                                        }
                                    }));
                                }
                            });
                            break;
                        default:
                            throw RobotRuleChangeTypeEnum.getBusinessException();
                    }
                }
                // 普通规则
                else {
                    List<FormOptionRespDTO> targetDataOptions = targetControlOptionMap.getOrDefault(robotRule.getRuleTargetId(), new ArrayList<>());
                    switch (ruleMatchingType) {
                        case CUSTOM:
                            // 自定义
                            targetData.setValues(robotRule.getValues());
                            break;
                        case MATCHING_FIELD:
                            // 匹配字段
                            if (sourceDataMap.containsKey(robotRule.getRuleSourceId())) {
                                // 源控件有效
                                ControlDataDTO sourceData = sourceDataMap.get(robotRule.getRuleSourceId());
                                // 复制订单控件数据
                                OrderDataUtil.copyControlData(sourceData, targetData, targetDataOptions);
                            }
                            break;
                        case DYNAMIC:
                            // 动态
                            dynamicRule.accept(robotRule);
                            targetData.setValues(robotRule.getValues());
                            break;
                        default:
                            throw MatchingTypeEnum.getBusinessException();
                    }
                }
            });
        });
    }

    /**
     * 订单数据 控件id与数据映射
     *
     * @param controlDataList controlDataList
     * @param initKey         控件id生成的key的方法
     * @return Map
     */
    public static <T> Map<T, List<String>> handleFlowControlData(List<ControlDataDTO> controlDataList, Function<Long, T> initKey) {
        Map<T, List<String>> variables = new HashMap<>();
        controlDataList.forEach(data -> {
            if (ControlCodeEnum.TABLE.getCode().equals(data.getControlCode())) {
                data.getTableValues().forEach(tableValues ->
                        OrderDataUtil.handleFlowControlData(tableValues, initKey)
                                .forEach((key, childValue) -> variables.merge(key, childValue, CollectionUtil::unionAll)));
            } else {
                T key = initKey.apply(data.getControlId());
                variables.put(key, OrderDataUtil.getControlValues(data.getControlCode(), data.getValues()));
            }
        });
        return variables;
    }

    /**
     * 获取订单控件数据值
     *
     * @param controlDTO           controlDTO
     * @param applicationOrderData applicationOrderData
     * @return List
     */
    public static List<String> orderDataValues(ControlDTO controlDTO, ApplicationOrderData applicationOrderData) {
        ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(controlDTO.getControlCode());
        List<ControlDataValueDTO> values = JSON.parseArray(applicationOrderData.getOrderData(), ControlDataValueDTO.class);
        return OrderDataUtil.getControlValues(controlCodeEnum, values);
    }

    /**
     * 控件数据格式化--显示使用
     *
     * @param controlDataDTO controlDataDTO
     * @return String
     */
    public static String controlDataValue(ControlDataDTO controlDataDTO) {
        ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(controlDataDTO.getControlCode());
        return controlCodeEnum.getControlDataToString().apply(controlDataDTO);
    }

    /**
     * 控件数据格式化--显示使用
     *
     * @param controlDataDTO controlDataDTO
     * @return List
     */
    public static List<String> controlDataValues(ControlDataDTO controlDataDTO) {
        return OrderDataUtil.controlDataValues(controlDataDTO.getControlCode(), controlDataDTO.getValues());
    }

    /**
     * 控件数据格式化--显示使用
     *
     * @param controlCode controlCode
     * @param dataValues  dataValues
     * @return List
     */
    public static List<String> controlDataValues(String controlCode, List<ControlDataValueDTO> dataValues) {
        return OrderDataUtil.controlDataValues(ControlCodeEnum.findByCode(controlCode), dataValues);
    }

    /**
     * 控件数据格式化--显示使用
     *
     * @param controlCodeEnum controlCodeEnum
     * @param dataValues      dataValues
     * @return List
     */
    public static List<String> controlDataValues(ControlCodeEnum controlCodeEnum, List<ControlDataValueDTO> dataValues) {
        return dataValues.stream().map(controlCodeEnum.getDataValueToString()).collect(Collectors.toList());
    }

    /**
     * 控件数据格式化--条件判断
     *
     * @param controlDataDTO controlDataDTO
     * @return List
     */
    public static List<String> getControlValues(ControlDataDTO controlDataDTO) {
        return OrderDataUtil.getControlValues(controlDataDTO.getControlCode(), controlDataDTO.getValues());
    }

    /**
     * 控件数据格式化--条件判断
     *
     * @param controlCode controlCode
     * @param dataValues  dataValues
     * @return List
     */
    public static List<String> getControlValues(String controlCode, List<ControlDataValueDTO> dataValues) {
        return OrderDataUtil.getControlValues(ControlCodeEnum.findByCode(controlCode), dataValues);
    }

    /**
     * 控件数据格式化--条件判断
     *
     * @param controlCodeEnum controlCodeEnum
     * @param dataValues      dataValues
     * @return List
     */
    public static List<String> getControlValues(ControlCodeEnum controlCodeEnum, List<ControlDataValueDTO> dataValues) {
        if (controlCodeEnum.valueUseId()) {
            return OrderDataUtil.getControlValueIds(dataValues).stream().map(e -> Long.toString(e)).collect(Collectors.toList());
        } else {
            return OrderDataUtil.getOrderDataValues(dataValues);
        }
    }

    /**
     * 复制控件值 value版
     *
     * @param controlCodeEnum controlCodeEnum
     * @param dataValues      dataValues
     * @return List
     */
    public static ControlDataValueDTO copyControlValues(ControlCodeEnum controlCodeEnum, List<ControlDataValueDTO> dataValues) {
        String value = dataValues.stream()
                .map(e -> controlCodeEnum.getDataValueToString().apply(e))
                .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS));
        return new ControlDataValueDTO(value);
    }

    /**
     * 获取订单控件数据中所有ids
     *
     * @param dataValues dataValues
     * @return List
     */
    public static List<Long> getControlValueIds(List<ControlDataValueDTO> dataValues) {
        List<Long> ids = new ArrayList<>();
        dataValues.forEach(dataValue -> {
            if (CollectionUtil.isNotEmpty(dataValue.getIds())) {
                ids.addAll(dataValue.getIds());
            }
            if (Objects.nonNull(dataValue.getId())) {
                ids.add(dataValue.getId());
            }
        });
        return ids;
    }

    /**
     * 获取订单控件数据中所有values
     *
     * @param dataValues dataValues
     * @return List
     */
    public static List<String> getOrderDataValues(List<ControlDataValueDTO> dataValues) {
        List<String> values = new ArrayList<>();
        dataValues.forEach(dataValue -> {
            if (StringUtils.isNotBlank(dataValue.getValue())) values.add(dataValue.getValue());
        });
        return values;
    }

    /**
     * 匹配相同下拉项
     *
     * @param selOptions     selOptions
     * @param controlOptions controlOptions
     * @return List
     */
    public static List<ControlDataValueDTO> matchingOptions(List<FormOptionRespDTO> selOptions, List<FormOptionRespDTO> controlOptions) {
        return OrderDataUtil.findSameOptions(selOptions, controlOptions).stream()
                .map(e -> new ControlDataValueDTO(e.getOptionId(), e.getOptionName()).setOtherInfo(e))
                .collect(Collectors.toList());
    }

    /**
     * 获取相同下拉项（相同optionId 或者相同optionName）
     *
     * @param selOptions     selOptions
     * @param controlOptions controlOptions
     * @return List
     */
    public static List<FormOptionRespDTO> findSameOptions(List<FormOptionRespDTO> selOptions, List<FormOptionRespDTO> controlOptions) {
        List<Long> selOptionIds = new ArrayList<>();
        List<String> selOptionNames = new ArrayList<>();
        selOptions.forEach(o -> {
            selOptionIds.add(o.getOptionId());
            selOptionNames.add(o.getOptionName());
        });

        return controlOptions.stream()
                .filter(e -> selOptionIds.contains(e.getOptionId()) || selOptionNames.contains(e.getOptionName()))
                .collect(Collectors.toList());
    }

    /**
     * 默认数据格式化
     *
     * @param controlDataDTO controlDataDTO
     * @return String
     */
    public static String defaultFormatValue(ControlDataDTO controlDataDTO) {
        return controlDataDTO.getValues().stream()
                .map(ControlDataValueDTO::getValue)
                .collect(Collectors.joining(PoiUtil.IMP_EXP_SEPARATORS));
    }

    /**
     * 获取下拉值
     *
     * @param dataValue dataValue
     * @return String
     */
    public static String getOptionName(ControlDataValueDTO dataValue) {
        String value = OrderDataUtil.getValueByOtherInfo(dataValue, NodeBaseDTO.class, NodeBaseDTO::getNodeName);
        if (StringUtils.isBlank(value)) {
            value = OrderDataUtil.getValueByOtherInfo(dataValue, FormOptionRespDTO.class, FormOptionRespDTO::getOptionName);
        }
        return value;
    }

    /**
     * 获取控件数据其他信息
     *
     * @param dataValue dataValue
     * @return String
     */
    public static <T> String getValueByOtherInfo(ControlDataValueDTO dataValue, Class<T> tClass, Function<T, String> get) {
        return OrderDataUtil.getValueByOtherInfo(dataValue, tClass, get, "");
    }

    /**
     * 获取控件数据其他信息
     *
     * @param dataValue dataValue
     * @return String
     */
    public static <T, V> V getValueByOtherInfo(ControlDataValueDTO dataValue, Class<T> tClass, Function<T, V> get, V defaultValue) {
        return OrderDataUtil.optionalValueByOtherInfo(dataValue, tClass, get).orElse(defaultValue);
    }

    /**
     * 获取控件数据其他信息
     *
     * @param dataValue dataValue
     * @return String
     */
    public static <T, V> Optional<V> optionalValueByOtherInfo(ControlDataValueDTO dataValue, Class<T> tClass, Function<T, V> get) {
        V v = get.apply(BeanUtil.copyProperties(dataValue.getOtherInfo(), tClass));
        return Optional.ofNullable(v);
    }

    /**
     * 从获取控件map中返回指定控件Optional
     *
     * @param controlMap controlMap
     * @param controlId  controlId
     * @return Optional
     */
    public static Optional<ControlDTO> getControlByMap(Map<Long, ControlDTO> controlMap, Long controlId) {
        if (controlMap.containsKey(controlId)) {
            return Optional.ofNullable(controlMap.get(controlId));
        } else {
            for (ControlDTO control : controlMap.values()) {
                for (ControlDTO childControl : control.getChildControls()) {
                    if (childControl.getControlId().equals(controlId)) {
                        return Optional.of(childControl);
                    }
                }
            }
            return Optional.empty();
        }
    }

    /**
     * 从获取控件数据map中返回指定控件数据列表（若目标控件id是表格中的数据，则获取表格整列数据）
     *
     * @param controlDataMap controlDataMap
     * @param controlId      controlId
     * @return Optional
     */
    public static List<ControlDataDTO> getOrderDataByMap(Map<Long, ControlDataDTO> controlDataMap, Long controlId) {
        return OrderDataUtil.getControlDataByMap(controlDataMap, controlId).map(ListUtil::toList)
                // orElseGet 有值不会执行
                .orElseGet(() -> controlDataMap.values().stream()
                        .filter(data -> !data.getTableValues().isEmpty())
                        .map(data -> OrderDataUtil.getOrderTableCell(data.getTableValues(), controlId))
                        .findFirst().orElse(new ArrayList<>()));
    }

    /**
     * 获取表格某一列数据
     *
     * @param tableValues tableValues
     * @param controlId   controlId
     * @return ArrayList
     */
    public static ArrayList<ControlDataDTO> getOrderTableCell(List<List<ControlDataDTO>> tableValues, Long controlId) {
        ArrayList<ControlDataDTO> list = new ArrayList<>();
        for (List<ControlDataDTO> row : tableValues) {
            row.stream().filter(cell -> cell.getControlId().equals(controlId)).findFirst().ifPresent(list::add);
        }
        return list;
    }

    /**
     * 从获取控件map中返回指定控件Optional
     *
     * @param controlDataMap controlDataMap
     * @param controlId      controlId
     * @return Optional
     */
    public static Optional<ControlDataDTO> getControlDataByMap(Map<Long, ControlDataDTO> controlDataMap, Long controlId) {
        return Optional.ofNullable(controlDataMap.get(controlId));
    }

    /**
     * 表格数据转Map
     *
     * @param tableValues tableValues
     * @return Map
     */
    public static Map<Integer, Map<Long, ControlDataDTO>> tableDataToMap(List<List<ControlDataDTO>> tableValues) {
        Map<Integer, Map<Long, ControlDataDTO>> tableDataMap = new LinkedHashMap<>();
        for (int i = 0; i < tableValues.size(); i++) {
            tableDataMap.put(i, StreamUtil.toOrderlyMapK(tableValues.get(i), ControlDataDTO::getControlId));
        }
        return tableDataMap;
    }

    /**
     * 修改表格整列数据
     *
     * @param cellDataMap            新列数据
     * @param tableDataMap           表格数据map
     * @param tableControlMap        表格子控件map
     * @param targetControlOptionMap 控件下拉项map
     * @param getControlDataForMap   从map中获取控件值，若不存在则初始化新控件数据 并且put到map中
     */
    public static void modifyTableCell(Map<Long, ControlDataDTO> cellDataMap,
                                       Map<Integer, Map<Long, ControlDataDTO>> tableDataMap,
                                       Map<Long, ControlDTO> tableControlMap,
                                       Map<Long, List<FormOptionRespDTO>> targetControlOptionMap,
                                       BiFunction<ControlDTO, Map<Long, ControlDataDTO>, ControlDataDTO> getControlDataForMap) {
        // 表格整列 覆盖值
        cellDataMap.forEach((controlId, data) -> {
            // 表格所有行
            tableDataMap.values().forEach(row -> {
                // 获取表格子控件信息
                OrderDataUtil.getControlByMap(tableControlMap, controlId).ifPresent(childTargetControl -> {
                    // 获取表格指定格子
                    ControlDataDTO childTargetData = getControlDataForMap.apply(childTargetControl, row);
                    // 格子下拉项
                    List<FormOptionRespDTO> targetDataOptions = targetControlOptionMap.getOrDefault(controlId, new ArrayList<>());
                    // 复制值
                    OrderDataUtil.copyControlData(data, childTargetData, targetDataOptions);
                    // 补充到行
                    row.put(childTargetData.getControlId(), childTargetData);
                });
            });
        });
    }

    /**
     * 过滤重复值的控件
     *
     * @param controlDataList controlDataList
     * @return List
     */
    public static List<ControlDataDTO> filterRepeat(List<ControlDataDTO> controlDataList) {
        Set<String> set = new HashSet<>();
        return controlDataList.stream()
                .filter(e -> {
                    String value = ControlCodeEnum.findByCode(e.getControlCode()).getControlDataToString().apply(e);
                    return StringUtils.isNotBlank(value) && set.add(value);
                })
                .collect(Collectors.toList());
    }

    /**
     * 过滤有效筛选条件
     *
     * @param judgeOrs   judgeOrs
     * @param controlIds 表单控件ids
     * @param targetIds  目标ids
     * @return List
     */
    public static List<JudgeOr> filterJudgeOrs(Collection<JudgeOr> judgeOrs, Collection<Long> controlIds, Collection<Long> targetIds) {
        return judgeOrs.stream()
                .peek(or -> or.setJudgeAnd(or.getJudgeAnd().stream()
                        .filter(and -> {
                            if (Objects.nonNull(controlIds) && !controlIds.contains(and.getControlId())) {
                                return false;
                            }
                            if (!ApplicationConstant.DEFAULT_CONTROL_ID.equals(and.getTargetId())) {
                                return targetIds.contains(and.getTargetId());
                            }
                            return true;
                        })
                        .toList()))
                .filter(or -> !or.getJudgeAnd().isEmpty())
                .collect(Collectors.toList());
    }

    /**
     * 比对订单数据是否有变动 （只比对新值传入控件，因为新值没有传入的控件，证明不改动该控件）
     *
     * @param newData           新数据
     * @param oldData           旧数据
     * @param triggerControlIds 监控哪些控件数据变动 为空时全部比对
     * @return boolean
     */
    public static boolean hasChange(Collection<ControlDataDTO> newData, Collection<ControlDataDTO> oldData, List<Long> triggerControlIds) {
        boolean all = Objects.isNull(triggerControlIds);
        Map<Long, ControlDataDTO> oldControlDataMap = StreamUtil.toMapK(oldData, ControlDataDTO::getControlId);
        for (ControlDataDTO newControlData : newData) {
            boolean in = all || triggerControlIds.contains(newControlData.getControlId());

            if (oldControlDataMap.containsKey(newControlData.getControlId())) {
                ControlDataDTO oldControlData = oldControlDataMap.get(newControlData.getControlId());

                // 在监控范围
                if (in) {
                    if (OrderDataUtil.hasChangeValues(newControlData, oldControlData)) {
                        return true;
                    }
                }

                // 检测表格行是否变动 （如果不是表格，二维数组为空，会返回false）
                if (OrderDataUtil.hasChangeTableValue(newControlData.getTableValues(), oldControlData.getTableValues(), triggerControlIds)) {
                    return true;
                }
            } else {
                // 旧值没有该控件 在监控范围 则返回true
                if (in) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取变动列表
     *
     * @param newData newData
     * @param oldData oldData
     * @return List
     */
    public static Map<Long, ControlDataDTO> getChangeMap(Collection<ControlDataDTO> newData, Collection<ControlDataDTO> oldData) {
        return StreamUtil.toMapK(getChangeList(newData, oldData), ControlDataDTO::getControlId);
    }

    /**
     * 获取变动列表
     *
     * @param newData newData
     * @param oldData oldData
     * @return List
     */
    public static List<ControlDataDTO> getChangeList(Collection<ControlDataDTO> newData, Collection<ControlDataDTO> oldData) {
        Map<Long, ControlDataDTO> oldControlDataMap = StreamUtil.toMapK(oldData, ControlDataDTO::getControlId);
        Map<Long, List<List<ControlDataDTO>>> oldTableValuesMap = StreamUtil.toMapKV(oldData, ControlDataDTO::getControlId, ControlDataDTO::getTableValues);
        return newData.stream()
                .filter(nd -> !oldControlDataMap.containsKey(nd.getControlId()) ||
                        OrderDataUtil.hasChangeValues(nd, oldControlDataMap.get(nd.getControlId())) ||
                        OrderDataUtil.hasChangeTableValue(nd.getTableValues(), oldTableValuesMap.getOrDefault(nd.getControlId(), new ArrayList<>()), null))
                .collect(Collectors.toList());
    }

    /**
     * 检查订单控件数据是否有变动
     *
     * @param newData newData
     * @param oldData oldData
     * @return boolean
     */
    public static boolean hasChangeValues(ControlDataDTO newData, ControlDataDTO oldData) {
        return OrderDataUtil.hasChangeValues(newData.getControlCode(), newData.getValues(), oldData.getValues());
    }

    /**
     * 检查订单控件数据是否有变动
     *
     * @param controlCode   controlCode
     * @param newDataValues newDataValues
     * @param oldDataValues oldDataValues
     * @return boolean
     */
    public static boolean hasChangeValues(String controlCode, List<ControlDataValueDTO> newDataValues, List<ControlDataValueDTO> oldDataValues) {
        if (Objects.equals(newDataValues, oldDataValues)) {
            return false;
        }
        if (Objects.isNull(oldDataValues)) {
            return true;
        }
        List<String> newValues = OrderDataUtil.getControlValues(controlCode, newDataValues);
        List<String> oldValues = OrderDataUtil.getControlValues(controlCode, oldDataValues);
        // 长度不一致，有变更
        if (newValues.size() != oldValues.size()) {
            return true;
        }
        // 长度一致，新值 有任何一个 不在 旧值，则有变更
        return newValues.stream().anyMatch(v -> !oldValues.contains(v));
    }

    /**
     * 检查表格数据是否有变动
     *
     * @param newTableValues    新数据
     * @param oldTableValues    旧数据
     * @param triggerControlIds 监控哪些控件数据变动 为空时全部比对
     * @return boolean
     */
    public static boolean hasChangeTableValue(List<List<ControlDataDTO>> newTableValues, List<List<ControlDataDTO>> oldTableValues, List<Long> triggerControlIds) {
        boolean all = Objects.isNull(triggerControlIds);
        boolean hasNew = CollectionUtil.isNotEmpty(newTableValues);
        boolean hasOld = CollectionUtil.isNotEmpty(oldTableValues);

        // 有新值
        if (hasNew) {
            int row = 0;
            for (Collection<ControlDataDTO> newRow : newTableValues) {
                if (hasOld && row <= oldTableValues.size() - 1) {
                    // 检查当前行 是否有变动
                    if (OrderDataUtil.hasChange(newRow, oldTableValues.get(row), triggerControlIds)) {
                        return true;
                    }
                } else {
                    // 旧值没有该行，只要在监控范围内直接返回true
                    if (all || StreamUtil.anyMatch(newRow, c -> triggerControlIds.contains(c.getControlId()))) {
                        return true;
                    }
                }
                row++;
            }
        }
        // 有旧值
        if (hasOld) {
            for (Collection<ControlDataDTO> oldRow : oldTableValues) {
                // 新值没有该行值，只要在监控范围内直接返回true
                return all || StreamUtil.anyMatch(oldRow, c -> triggerControlIds.contains(c.getControlId()));
            }
        }
        return false;
    }

    /**
     * 目标副本创建副本，然后向目标副本 补充 相比源 缺失的
     *
     * @param source 源
     * @param target 目标
     * @return 副本
     */
    public static List<ControlDataDTO> copyAndSupply(List<ControlDataDTO> source, List<ControlDataDTO> target) {
        // 副本
        List<ControlDataDTO> copyData = StreamUtil.transListT(target, o -> o.copy(true));
        // 副本map
        Map<Long, ControlDataDTO> dataMap = StreamUtil.toOrderlyMapK(copyData, ControlDataDTO::getControlId);
        // 补充缺失
        copyData.addAll(StreamUtil.transListFT(source, o -> !dataMap.containsKey(o.getControlId()), o -> o.copy(true)));
        return copyData;
    }
}
